using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace AHWrapper{
	
	public class Game{
		
		public List<Investigator> investDeck;
		public List<Investigator> investInPlay;
		public List<Gate> gateDeck;
		public List<Gate> gateInPlay;
		public List<MythCard> mythDeck;
		public MythCard mythInPlay;
		public Investigator curPlayer;
		public int numInvest;
		public Board gBoard;
		public PhaseType phase;
		public int phaseCounter;
		public int monsToDealWith;
		
		
		public Game(int pPlayers){
		//Constructor, accepts number of investigators to user
			//set number of investigators
			numInvest=pPlayers;
			
			//initialize investigator deck
			createInvestDeck();
			//randomly select #pPlayers from investigator deck to use
			selectInvestigators(pPlayers);
			//store pointer to current investigator
			curPlayer=investInPlay[0];
			
			//initialize other decks
			createGateDeck();
			createMythDeck();
			
			//construct board
			gBoard = new Board();
			//Initialize phase trackers
			phase=PhaseType.Upkeep1;
			phaseCounter=0;
		}
		
		public void createInvestDeck(){
		//initializes investigator deck (holds all investigators from file)
			//create investigator list
			investDeck = new List<Investigator>();
			
			//Open file containing investigator data
			TextReader tr = new StreamReader("investigators.txt");
			
			//Read file by line, create investigator and add it to the deck
			string line;
			string[] arInfo = new string[18];
			while((line=tr.ReadLine())!=null){
				arInfo = line.Split(',');
				investDeck.Add(new Investigator(arInfo[0],Convert.ToInt32(arInfo[1]),Convert.ToInt32(arInfo[2]),arInfo[3],Convert.ToInt32(arInfo[4]),Convert.ToInt32(arInfo[5]),
				                                Convert.ToInt32(arInfo[6]),Convert.ToInt32(arInfo[7]),Convert.ToInt32(arInfo[8]),Convert.ToInt32(arInfo[9]),Convert.ToInt32(arInfo[10]),Convert.ToInt32(arInfo[11]),
												Convert.ToInt32(arInfo[12]),Convert.ToInt32(arInfo[13]),Convert.ToInt32(arInfo[14]),Convert.ToInt32(arInfo[15]),Convert.ToInt32(arInfo[16]),arInfo[17]));
			}
			//close the file
			tr.Close();
		}
		
		public void selectInvestigators(int pNumPlayers){
		//move #pNumPlayers random players from investigator deck to in play
			//create list of investigators in play
			investInPlay = new List<Investigator>();
			
			//Select [pNumPlayers] investigators from the deck and remove them and put them into play
			Random rand = new Random();
			for(int i=pNumPlayers; i>0; i--){
				int x = rand.Next(0,investDeck.Count-1);
				investInPlay.Add(investDeck[x]);
				investDeck.Remove(investDeck[x]);
			}
		}
		
		public Investigator getCurPlayer(){
		//returns current investigator
			return curPlayer;
		}
		
		public void nextPlayer(){
		//Changes current player to the next player in line
			int curIndex=0;
			int count=0;
			//find index of investigator in play
			foreach(Investigator invest in investInPlay){
				if(curPlayer.name==invest.name){
					curIndex=count;
				}
				count++;
			}
			//if investigator is last in list move to first investigator
			if(curIndex==(investInPlay.Count-1)){
				curPlayer=investInPlay[0];
			//otherwise use the next investigator in the list	
			}else{
				curPlayer=investInPlay[curIndex+1];
			}	
		}
		
		public void nextPhase(){
		//Increases the phase counter if not everyone has gone yet, otherwise if advances to the next phase
			//If everyone has gone or the mythos phase is active
			if(phaseCounter==(numInvest-1)||phase==PhaseType.Myth || phase==PhaseType.Myth1){
				//restart phase counter
				phaseCounter=0;
				//If we are in the mythos phase(last phase) wrap back to first phase (upkeep)
				if(phase==PhaseType.Myth || phase==PhaseType.Myth1){
					nextPlayer();
					phase=PhaseType.Upkeep;
				}else{ //otherwise just move to the next phase in line
					phase++;
				}
			}else{ //if everyone hasn't gone and the mythos phase is not active just increase the phase counter
				phaseCounter++;
			}
		}
		
		public Location getCurLoc(){
		//get location of the current investigator
			return gBoard.getLoc(curPlayer);
		}
		
		public void stopMoves(){
		//sets current players remaining moves to 0
			curPlayer.stopMoves();
		}
		
		public bool setStats(int pSpeed,int pFight, int pLore){
		//changes investigator's stats, returns true is change is allowed
			if(curPlayer.setStats(pSpeed,pFight,pLore,phase==PhaseType.Upkeep1)){
				end();
				return true;
			}else{
				return false;
			}
		}
		
		
		public void move(int pDirection){
		//move the investigator in the corresponding direction
			//if the player has moves available call the move method on the board
			if(curPlayer.getMovesLeft()>0){
				gBoard.move(curPlayer,pDirection);
				curPlayer.moved();
			}else{//otherwise alert the user they are out of moves and move the next player and/or phase
				Console.WriteLine("Out of moves");
				end();
			}
		}
		
		public void upkeep(){
			if(!curPlayer.delayed){
				curPlayer.resetMoves();
			}else{
				curPlayer.stopMoves();
				curPlayer.delayed=false;
			}
		}
		public bool moveStart(){
			if(curPlayer.getMovesLeft()>0){
				return true;
			}else{
				end();
				return false;
			}
		}
		
		public void createGateDeck(){
		//assemble gate deck
			gateInPlay = new List<Gate>();
			gateDeck = new List<Gate>();
			TextReader tr = new StreamReader("gate.txt");
			string line;
			//read file line by line, create gate from line and add it to the gateDeck list
			string[] arInfo = new string[2];
			while((line=tr.ReadLine())!=null){
				arInfo = line.Split(',');
				gateDeck.Add(new Gate(arInfo[0],Convert.ToInt32(arInfo[1])));
			}
			tr.Close();
		}
		public Gate selectGate(){
		//randomly retrieves gate from deck and puts it in play
			Random rand = new Random();
			int x=rand.Next(0,gateDeck.Count-1);
			Gate selectedGate=gateDeck[x];
			//move selected gate from the deck to in play
			gateInPlay.Add(selectedGate);
			gateDeck.Remove(selectedGate);
			return selectedGate;
		}

		public void createMythDeck(){
		//assemble mythos deck
			mythDeck = new List<MythCard>();
			TextReader tr = new StreamReader("mythCard.txt");
			string line;
			//read mythos details from file line by line, create a mythCard and add it to the "deck"
			string[] arInfo = new string[2];
			while((line=tr.ReadLine())!=null){
				arInfo = line.Split(',');
				mythDeck.Add(new MythCard(arInfo[0],Convert.ToInt32(arInfo[1])));
			}
			tr.Close();
		}
		public MythCard selectMythCard(){
			Random rand = new Random();
			int x=rand.Next(0,mythDeck.Count);
			mythInPlay=mythDeck[x];
			//move selected gate from the deck to in play
			return mythInPlay;
		}
		public void myth(){
			//grab a gate from the gate deck and put it into play
			Gate openGate=selectGate();
			//place gate in a location (unstable location soon)
			if(gBoard.placeGate(openGate,selectMythCard().actLoc)){
			//if placing the gate fails return gate to deck and spawn a mon from every gate
			}else{
				returnGate(openGate);
				gBoard.spawn();
			}
			//spawn a mon from every gate
			gBoard.spawn();
			end();
			
		}
		//returns a gate to the deck (called because gate is already present at location or gate trophy has been used)
		public void returnGate(Gate pRetGate){
			gateDeck.Add(pRetGate);
			gateInPlay.Remove(pRetGate);
		}
		
		public int encTest(bool first){
		//checks to see if 
			if(first){
				monsToDealWith=gBoard.encTest(getCurLoc());
			}
			return monsToDealWith;
		}
		
		public int mEncSneak(){
			Mons occupant=gBoard.getOccupant(getCurLoc(),monsToDealWith-1);
			if(curPlayer.check(Constants.Sneak,occupant.sModifier)){
				monsToDealWith--;
				if(monsToDealWith==0){
					if(curPlayer.getMovesLeft()>0){
						return Constants.MenuLoc;
					}
					else{
						end();
						return Constants.MenuNext;
					}
				}else{
					return Constants.MenuEnc;
				}
			}else{
				return mEncFight();
			}	
			
		}
		public int mEncFight(){
			curPlayer.stopMoves();
			Mons occupant=gBoard.getOccupant(getCurLoc(),monsToDealWith-1);
			
			while(true){
				if(!curPlayer.check(Constants.Will,occupant.hModifier)){
					curPlayer.stats[Constants.Sanity,Constants.Cur]-=occupant.hDam;
					if(curPlayer.stats[Constants.Sanity,Constants.Cur]<1){
						curPlayer.delayed=true;
						curPlayer.stats[Constants.Sanity,Constants.Cur]=1;
						gBoard.move(curPlayer,"Sanitarium");
						end();
						return Constants.MenuNext;
					}
				}
				if(!curPlayer.check(Constants.Fight,occupant.fModifier)){
					curPlayer.stats[Constants.Stamina,Constants.Cur]-=occupant.sDam;
					if(curPlayer.stats[Constants.Stamina,Constants.Cur]<1){
						curPlayer.delayed=true;
						curPlayer.stats[Constants.Stamina,Constants.Cur]=1;
						gBoard.move(curPlayer,"Hospital");
						end();
						return Constants.MenuNext;
					}
				}else{
					occupant.curTough-=1;
					if(occupant.curTough<1){
						monsToDealWith--;
						//remove mons from space
						gBoard.removeOccupant(getCurLoc(),monsToDealWith-1);
						//add mons to invest as troph
						if(monsToDealWith==0){
							end();
							return Constants.MenuNext;
						}else{
							return Constants.MenuEnc;
						}
						
					}
				}
			}	
		}
		public void end(){
		//Ends current investigators part of phase
			nextPlayer();
			nextPhase();
		}

	}
}